/**
 * Anderground project - Subway maps processor application.
 * Copyright (C) 2008-2009 Eldar Abusalimov, Ilya Shurigyn
 * 
 * This file is part of Anderground.
 * 
 * Anderground is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * Anderground is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Anderground.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.anderground.modules.drawer.rapid;

import static org.anderground.modules.drawer.rapid.Config.hubBackRadius;
import static org.anderground.modules.drawer.rapid.Config.hubRadius;
import static org.anderground.modules.drawer.rapid.Config.stationBackRadius;
import static org.anderground.modules.drawer.rapid.Config.stationRadius;

import java.util.ArrayList;
import java.util.HashMap;

import org.anderground.core.drawer.Calculator;
import org.anderground.core.graphics.Canvas;
import org.anderground.core.graphics.Color;
import org.anderground.core.graphics.Paint;
import org.anderground.core.graphics.PointF;
import org.anderground.core.graphics.RadialGradient;
import org.anderground.core.graphics.RectF;
import org.anderground.core.model.Line;
import org.anderground.core.model.Station;
import org.anderground.internal.graphics.abstaractions.AbstractPaint.Style;

/**
 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
 */
class Node {

	private static Paint simplePaint = new Paint();

	private static Paint complexPaint = new Paint();

	private static Paint backSimplePaint = new Paint();

	private static Paint backComplexPaint = new Paint();

	static {

		simplePaint.setAntiAlias(true);
		simplePaint.setStrokeCap(Paint.Cap.ROUND);

		complexPaint.setAntiAlias(true);
		complexPaint.setStrokeCap(Paint.Cap.BUTT);
		complexPaint.setStyle(Style.FILL_AND_STROKE);

		backSimplePaint.setAntiAlias(true);
		backSimplePaint.setStrokeCap(Paint.Cap.ROUND);
		backSimplePaint.setColor(Color.WHITE);

		backComplexPaint.setAntiAlias(true);
		backComplexPaint.setStrokeCap(Paint.Cap.ROUND);
		backComplexPaint.setColor(Color.LTGRAY);

	}

	/** a set of stations represented in this Node instance */
	private ArrayList<Station> stations;

	/** neighbor-to-link mapping */
	private HashMap<Node, Link> linksMap = new HashMap<Node, Link>();

	/** a set of colors */
	private ArrayList<Integer> colors = new ArrayList<Integer>();

	private boolean simple;

	private PointF coordF, pointF = new PointF();

	private RectF arcRectF = new RectF();

	public Node(Station station, PointF coordF) {
		simple = true;
		stations = new ArrayList<Station>();
		stations.add(station);
		if (station.getLines().length == 1) {
			colors.add(station.getLines()[0].getColor());
		} else {
			colors.add(Config.DEFAULT_COLOR);
		}

		this.coordF = coordF;
	}

	public Node(ArrayList<Station> stations, PointF coordF) {
		simple = false;
		this.stations = stations;
		for (Station station : stations) {
			for (Line line : station.getLines()) {
				if (!colors.contains(line.getColor())) {
					colors.add(line.getColor());
				}
			}
		}

		this.coordF = coordF;
	}

	public Link searchNeighbor(Node neighborNode) {
		Link neighborLink = linksMap.get(neighborNode);
		if (neighborLink == null) {
			neighborLink = new Link(this, neighborNode);
		}
		return neighborLink;
	}

	void addNeighbor(Node neighborNode, Link link) {
		this.linksMap.put(neighborNode, link);
	}

	public void applyCalculator(Calculator calculator) {
		calculator.convert(coordF, pointF);
	}

	public void draw(Canvas canvas) {
		if (simple) {
			canvas.drawPoint(pointF, backSimplePaint);
			simplePaint.setShader(new RadialGradient(pointF.x + 1,
					pointF.y + 1, (float) (stationRadius * 1.3), Color.WHITE,
					colors.get(0)));
			canvas.drawPoint(pointF, simplePaint);
		} else {
			canvas.drawPoint(pointF, backComplexPaint);
			arcRectF.set(pointF.x - hubRadius / 2, pointF.y - hubRadius / 2,
					pointF.x + hubRadius / 2, pointF.y + hubRadius / 2);
			if (colors.size() != 0) {
				float sector = 360 / colors.size();
				float angle = 90;
				for (int color : colors) {
					complexPaint.setShader(new RadialGradient(pointF.x + 1,
							pointF.y + 1, (float) (hubRadius * 1.3),
							Color.WHITE, color));
					canvas.drawArc(arcRectF, angle, sector, complexPaint);
					angle += sector;
				}
			}
		}
	}

	public PointF getCoordF() {
		return coordF;
	}

	public PointF getPointF() {
		return pointF;
	}

	public ArrayList<Station> getStations() {
		return stations;
	}

	public static void setup() {
		simplePaint.setStrokeWidth(stationRadius * 2);
		complexPaint.setStrokeWidth(hubRadius);
		backSimplePaint.setStrokeWidth(stationBackRadius * 2);
		backComplexPaint.setStrokeWidth(hubBackRadius * 2);
	}

	public HashMap<Node, Link> getLinksMap() {
		return linksMap;
	}

}
